package com.only4play.filter;

import com.only4play.common.model.GeneralResponse;
import com.only4play.constant.Oauth2Constant;
import com.only4play.constant.SSOConstant;
import com.only4play.domain.model.RpcAccessToken;
import com.only4play.domain.model.SessionAccessToken;
import com.only4play.utils.Oauth2Utils;
import com.only4play.utils.SessionUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

/**
 * @author liyuncong
 * @version 1.0
 * @file LoginFilter
 * @brief 登录过滤器
 * @details 登录过滤器
 * @date 2023-11-19
 * <p>
 * Edit History
 * ----------------------------------------------------------------------------
 * DATE                     NAME               DESCRIPTION
 * 2023-11-19               liyuncong          Created
 */
@Slf4j
public class LoginFilter extends AbstractClientFilter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

    }

    @Override
    public boolean isAccessAllowed(HttpServletRequest request, HttpServletResponse response) throws IOException {
        SessionAccessToken sessionAccessToken = SessionUtils.getAccessToken(request);
        // 本地session中已存在，且accessToken没有过期或者refreshAccessToken成功，直接返回
        if (Objects.nonNull(sessionAccessToken) && (!sessionAccessToken.isExpired())
            || Objects.nonNull(sessionAccessToken) && refreshToken(sessionAccessToken.getRefreshToken(), request)) {
            return true;
        }
        String code = request.getParameter(Oauth2Constant.AUTH_CODE);
        if (StringUtils.isNotBlank(code)) {
            // 获取accessToken
            getAccessToken(code, request);
            // 去掉URL中的授权码参数，在跳转一次当前地址
            redirectLocalAndRemoveCode(request, response);
        } else {
            // 重定向到登录地址
            redirectLogin(request, response);
        }
        return false;
    }

    protected boolean refreshToken(String refreshToken, HttpServletRequest request) {
        return false;
    }

    protected void getAccessToken(String code, HttpServletRequest request) {
        GeneralResponse<RpcAccessToken> response = Oauth2Utils.getAccessToken(getServerUrl(), getAppId(), getAppSecret(), code);
        if (Objects.isNull(response) || Objects.isNull(response.getPayload())) {
            return;
        }
        RpcAccessToken accessToken = response.getPayload();
        setAccessTokenInSession(accessToken, request);
    }

    private boolean setAccessTokenInSession(RpcAccessToken rpcAccessToken, HttpServletRequest request) {
        if (Objects.isNull(rpcAccessToken)) {
            return false;
        }
        // 记录accessToken到本地session
        SessionUtils.setAccessToken(request, rpcAccessToken);

        // 记录本地session和accessToken映射
        recordSession(request, rpcAccessToken.getAccessToken());
        return true;
    }

    private void recordSession(final HttpServletRequest request, String accessToken) {
        final HttpSession session = request.getSession();
        getSessionMappingStorage().removeBySessionById(session.getId());
        getSessionMappingStorage().addSessionById(accessToken, session);
    }

    protected void redirectLocalAndRemoveCode(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String currentUrl = getCurrentUrl(request);
        currentUrl = currentUrl.substring(0, currentUrl.indexOf(Oauth2Constant.AUTH_CODE) - 1);
        response.sendRedirect(currentUrl);
    }

    protected void redirectLogin(HttpServletRequest request, HttpServletResponse response) throws IOException {
        StringBuilder builder = new StringBuilder();
        builder.append(getServerUrl())
            .append(SSOConstant.LOGIN_URL)
            .append("?")
            .append(Oauth2Constant.APP_ID).append("=").append(getAppId())
            .append("&")
            .append(SSOConstant.REDIRECT_URI).append("=").append(getCurrentUrl(request));
        String loginUrl = URLDecoder.decode(builder.toString(), StandardCharsets.UTF_8);
        response.sendRedirect(loginUrl);
    }

    private String getCurrentUrl(HttpServletRequest request) {
        return request.getRequestURL() +
            (request.getQueryString() == null ? "" : "?" + request.getQueryString());
    }
}
